﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using PowerMonitor.BaseCtrl;
using PowerMonitor.Properties;

namespace PowerMonitor.ModbusDev
{
    public partial class ScriptEdit : Form
    {
        BaseDevice CurDev = null;
        DevDataItem CurItem = null;

        StringBuilder strExpession = new StringBuilder();
        ScriptSource CurCode = null;

        public ScriptEdit()
        {
            InitializeComponent();
        }
        public ScriptEdit(BaseDevice dev)
        {
            InitializeComponent();
            CurDev = dev;
        }
        private void ScriptEdit_Load(object sender, EventArgs e)
        {
            if (CurDev!= null)
            {
                for (int i = 0;i < CurDev.GetDataItemCnt();i++)
                {
                    dataList.Items.Add(CurDev.GetDataItem(i).Name);
                }
                CurItem = CurDev.GetDataItem(0);
                txtExpression.Text = CurItem.Expression;
                if (dataList.Items.Count > 0)
                {
                    dataList.SelectedIndex = 0;
                }
            }
        }

        private void btnExecute_Click(object sender, EventArgs e)
        {
            txtErrorList.Clear();
            try
            {
                if (CurCode != null && strExpession.Length>0)
                {
                    var scode = AppMain.ScptEngine.CreateScope();
                    if (dataList.Enabled)
                    {
                        scode.SetVariable("bytes", CurItem.RawBytes);  // 设置全局变量
                    }
                    else
                    {
                        scode.SetVariable("DataList", CurDev.GetDataList());          // 设置全局变量
                    }
                    
                    var actual = CurCode.Execute<object>(scode);
                    txtErrorList.AppendText(Resources.txtScriptCompileResult + (actual != null ? actual.ToString():Resources.txtNoResult));
                }
            }
            catch (Exception ex)
            {
                CurItem.Expression = "";
                MessageBox.Show(ex.Message);
            }

        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            txtErrorList.Clear();
            if (dataList.Enabled)
            {
                CurItem.Expression = strExpession.ToString();
            } 
            else
            {
                CurDev.Expression = strExpession.ToString();
            }
            txtErrorList.AppendText(Resources.MsgSaveSucceed);
        }
        private void ScriptEdit_FormClosing(object sender, FormClosingEventArgs e)
        {
            strExpession = null;
            CurCode = null;
        }
        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void dataList_SelectedIndexChanged(object sender, EventArgs e)
        {

            if (!string.IsNullOrEmpty(strExpession.ToString()) && CurItem!= null)
            {
                CurItem.Expression = strExpession.ToString();
            }

            CurItem = CurDev.GetDataList().Find(sss => sss.Name == dataList.SelectedItem as string);
            if (CurItem != null)
            {
                txtExpression.Clear();
                txtExpression.Text = CurItem.Expression;
            }
        }

        private void txtExpression_TextChanged(object sender, EventArgs e)
        {
            strExpession.Clear();
            if (txtExpression.Text.Trim().Length > 0)
            {
                strExpession.Append(txtExpression.Text);
            }
            if (strExpession.Length>0)
            {
                CurCode = AppMain.ScptEngine.CreateScriptSourceFromString(strExpession.ToString());
                //CurCode = AppMain.ScptEngine.CreateScriptSourceFromString(AppMain.IronPythonHeader.ToString() + strExpession.ToString());
                ErrorDump errList = new ErrorDump();
                try
                {
                    CurCode.Compile(errList);
                    txtErrorList.Clear();
                    if (errList.Errors.Count==0)
                    {
                        txtErrorList.AppendText(string.Format("{0} Errors,{1} Warnings",0,0));
                    }
                    else
                    {
                         var ErrCnt = (from sss in errList.Errors
                                      where sss.Severity == ErrorInfo.SeverityType.Error
                                      select sss).Count();
                         int WarningCnt = errList.Errors.Count - ErrCnt;
                         txtErrorList.AppendText(string.Format("{0} Errors,{1} Warnings\n",ErrCnt,WarningCnt));
                        foreach(ErrorInfo err in errList.Errors)
                        {
                            txtErrorList.AppendText(string.Format("{0}:{1}\n", err.Severity.ToString(), err.Message));
                        }
                    }
                    
                }
                catch (Exception ex)
                {
                    txtErrorList.AppendText(ex.Message);
                }
            }
            else
            {
                CurCode = null;
            }
        }

        private void cbbDevice_CheckStateChanged(object sender, EventArgs e)
        {
            if (cbbDevice.CheckState == CheckState.Checked)
            {
                dataList.Enabled = false;
                txtExpression.Clear();
                txtExpression.Text = CurDev.Expression;
            }
            else
            {
                if (txtExpression.Text.Trim().Length>0)
                {
                    CurDev.Expression = txtExpression.Text.Trim();
                }
                dataList.Enabled = true;
                txtExpression.Clear();
                txtExpression.Text = CurItem.Expression;
            }
        }

        private void btnImport_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofDlg = new OpenFileDialog();
            ofDlg.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
            ofDlg.Filter = Resources.txtFilterScript_py;
            ofDlg.Multiselect = false;
            if (ofDlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    txtExpression.LoadFile(ofDlg.FileName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }
                MessageBox.Show(Resources.MsgImportSucceed, Resources.msgTitleTip);
            }
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            if (txtExpression.Text.Trim().Length == 0)
            {
                MessageBox.Show(Resources.MsgPleaseInputContent, Resources.msgTitleTip);
                return;
            }
            SaveFileDialog save = new SaveFileDialog();
            save.DefaultExt = "ini";
            save.AddExtension = true;
            save.Filter = Resources.txtFilterScript_py;
            save.DefaultExt = "*.py";
            save.Title = Resources.txtExportPath;
            save.FileName = dataList.SelectedItem != null ?dataList.SelectedItem.ToString():Resources.txtNewScript;
            //save.InitialDirectory = AppMain.StartPath;
            if (save.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    txtExpression.SaveFile(save.FileName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }
                MessageBox.Show(Resources.MsgExportSucceed, Resources.msgTitleTip);
            }
        }

        private void btnHelp_Click(object sender, EventArgs e)
        {
            txtErrorList.LoadFile(AppMain.StartPath + "\\UserConfig\\help.rtf");
        }


    }
    public class ErrorInfo
    {
        public enum SeverityType
        {
            Error,
            Warning
        };
        public string Message;
        public int Line;
        public SeverityType Severity;
    }

    class ErrorDump : ErrorListener
    {
        List<ErrorInfo> errors = new List<ErrorInfo>();
        public List<ErrorInfo> Errors
        {
            get { return errors; }
        }

        public override void ErrorReported(ScriptSource source, string message, SourceSpan span, int errorCode, Severity severity)
        {
            ErrorInfo error = new ErrorInfo();
            error.Message = message;
            error.Line = span.Start.Line - 1;

            switch (severity)
            {
                case Severity.Error:
                case Severity.FatalError:
                    error.Severity = ErrorInfo.SeverityType.Error;
                    break;
                case Severity.Ignore:
                case Severity.Warning:
                    error.Severity = ErrorInfo.SeverityType.Warning;
                    break;
            }
            errors.Add(error);
        }
    } 
}
